-module(routeroutputline).

-include_lib("records.hrl").

-export([init/6]).

init(SrcId, K, Rate, DestId, DestPid, Time)->
  Outline = #routerout{source_id=SrcId, blength=K, rate=Rate, dest_id=DestId, dest_tid=DestPid},
  run(Outline, Time).

run(Outline, Time) ->
  #routerout{source_id=SrcId, blength=K, rate=Rate, dest_id=Did, dest_tid=Dpid, buffers=Buffers}=Outline,
  receive
    {From, dest_id} ->
      From!{self(), Did},
      run(Outline, Time);
    {From, finish} ->
      From ! ok,
      run(Outline, Time);
    {From, close} ->
      From ! close;
    {From, {add, Packet}}->
      if
        length(Buffers)<K ->
          NewPacket = timestamp_packet(arrive, SrcId, Rate, Packet, Time),
          NewBuffer = lists:append(Buffers, [NewPacket]),
          From ! {self(), added};
        true->
          NewBuffer = Buffers,
          From ! {self(), full}
      end,
      run(Outline#routerout{buffers=NewBuffer}, Time);
    {_, {time_change, NewTime}} ->
      NewBuffer = transfer(Buffers, SrcId, Rate, NewTime, 1, Dpid),
      run(Outline#routerout{buffers=NewBuffer}, NewTime)
  end.

transfer(Buffers, SrcId, Rate, NewTime, UseTime, Dpid)->
  if
    UseTime>0 ->
      case Buffers of
        [] ->
          [];
        [H|T]->
          NewPacket=timestamp_packet(bprocess, SrcId, Rate, H, NewTime),
          #packet{ntime=NeedTime}=NewPacket,
          NewNeedTime = NeedTime - UseTime,
          PPacket = NewPacket#packet{ntime=NewNeedTime},
          if
            NewNeedTime>0 ->
              [PPacket|T];
            true ->
              NewUseTime=-NewNeedTime,
              Dpid ! {self(), {packet, timestamp_packet(leave, SrcId, Rate, PPacket, NewTime-NewUseTime)}},
              transfer(T, SrcId, Rate, NewTime, NewUseTime, Dpid)
          end
      end;
    true ->
      Buffers
  end.

timestamp_packet(Opt, SrcId, Rate, Packet, Time) ->
  #packet{timestamps=PTimestamps, plength=Plength}= Packet,
  case Opt of
    arrive ->
      Timestamp = #timestamp{source_id=SrcId, atime=Time},
      Packet#packet{ntime=(Plength/Rate),timestamps=[Timestamp|PTimestamps]};
    bprocess ->
      [Timestamp|Other] = PTimestamps,
      #timestamp{ptime=PTime} = Timestamp,
      case PTime of
        undefined ->
          NewTime = Time;
        _ ->
          NewTime = PTime
      end,
      Packet#packet{timestamps=[Timestamp#timestamp{ptime=NewTime}|Other]};
    leave ->
      [Timestamp|Other] = PTimestamps,
      Packet#packet{timestamps=[Timestamp#timestamp{ltime=Time}|Other]}
  end.
